using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[Serializable]
public class BaseCharge
{
	private delegate IEnumerator WaitFunction(float streng, float maxDistance, Vector3 startPoint, Vector3 direction, LayerMask layer, float distance);

	private delegate IEnumerator WaitCone(float damage, float streng, float maxDistance, Vector3 startPoint, Vector3 direction, LayerMask layer);

	public ChargeType type;

	[Space(10f)]
	public GameObject chargePrefab;

	public DamageType damageType = DamageType.Kinetic;

	public WeaponEffectSettings[] effects;

	[Space(10f)]
	public Vector3 directionModifire = Vector3.zero;

	[Space(10f)]
	public float weight = 1f;

	public float updateTime = 0.1f;

	public Collider ignoreCollider;

	public Collider[] ignoreColliders;

	private BaseWeapon owner;

	private float damage;

	[SerializeField]
	private int maxCountOfRemainingOnScene = 9;

	private LinkedList<GameObject> remainingOnScene = new LinkedList<GameObject>();

	private WaitFunction wait;

	private WaitCone waitCone;

	public void Init(BaseWeapon weapon)
	{
		owner = weapon;
	}

	public void Shoot(float damage, float streng, float maxDistance, Vector3 startPoint, Vector3 direction, LayerMask layer, float distance)
	{
		this.damage = damage;
		switch (type)
		{
		case ChargeType.Bullet:
			ShootBullet(streng, maxDistance, startPoint, direction, layer, distance);
			break;
		case ChargeType.Area:
			owner.RiseEvent(owner, "OnlineShoot", Vector3.zero);
			ShootCone(streng, maxDistance, startPoint, direction, layer);
			break;
		case ChargeType.Mele:
			owner.RiseEvent(owner, "OnlineShoot", Vector3.zero);
			ShootMele(streng, maxDistance, startPoint, direction, layer, distance);
			break;
		case ChargeType.Projectile:
			owner.RiseEvent(owner, "OnlineShoot", Vector3.zero);
			ShootProjectile(streng, maxDistance, startPoint, direction, layer);
			break;
		case ChargeType.Homing:
			owner.RiseEvent(owner, "OnlineShoot", Vector3.zero);
			ShootHoming(streng, maxDistance, startPoint, direction, layer);
			break;
		case ChargeType.Remaining:
			owner.RiseEvent(owner, "OnlineShoot", Vector3.zero);
			ShootRemaining(streng, maxDistance, startPoint, direction, layer);
			break;
		case ChargeType.Growing:
			owner.RiseEvent(owner, "OnlineShoot", Vector3.zero);
			ShootGrowing(streng, maxDistance, startPoint, direction, layer);
			break;
		case ChargeType.Continuous:
			owner.RiseEvent(owner, "OnlineShoot", Vector3.zero);
			ShootContinuous(streng, maxDistance, startPoint, direction, layer, distance);
			break;
		}
	}

	private void ShootMele(float streng, float maxDistance, Vector3 startPoint, Vector3 direction, LayerMask layer, float distance)
	{
		wait = UpdateMeleDamague;
		owner.StartCoroutine(wait(streng, maxDistance, startPoint, direction, layer, distance));
	}

	private IEnumerator UpdateMeleDamague(float streng, float maxDistance, Vector3 startPoint, Vector3 direction, LayerMask layer, float distance)
	{
		yield return new WaitForSeconds(updateTime);
		Collider[] collider = Physics.OverlapSphere(startPoint + direction, maxDistance, layer);
		List<GameObject> demaged = new List<GameObject>();
		for (int i = 0; i < collider.Length; i++)
		{
			Mortal mortal = collider[i].GetComponentInParent<Mortal>();
			if ((!(collider[i].tag == "ShootHead") || !(UnityEngine.Random.Range(0f, 1f) < 0.75f)) && mortal != null && !demaged.Contains(mortal.gameObject))
			{
				demaged.Add(mortal.gameObject);
				SendDamage(mortal, damage, collider[i]);
			}
		}
	}

	private void ShootBullet(float streng, float maxDistance, Vector3 startPoint, Vector3 direction, LayerMask layer, float distance)
	{
		wait = UpdateBulletDamague;
		owner.StartCoroutine(wait(streng, maxDistance, startPoint, direction, layer, distance));
	}

	private IEnumerator UpdateBulletDamague(float streng, float maxDistance, Vector3 startPoint, Vector3 direction, LayerMask layer, float distance)
	{
		RaycastHit hit = default(RaycastHit);
		Ray ray = new Ray(startPoint, direction);
		Vector3 endPoint2 = Vector3.zero;
		if (owner == GameController.instance.playerScript.weaponManager.currentWeaponScript && distance < 1f)
		{
			ray = GameController.instance.playerScript.enemyWatcher.FromCenterScreenToAimHUD();
		}
		if (Physics.Raycast(ray, out hit, maxDistance, layer))
		{
			Mortal mortal = hit.collider.gameObject.GetComponentInParent<Mortal>();
			if (mortal == null)
			{
				mortal = hit.collider.gameObject.GetComponentInChildren<Mortal>();
			}
			if (mortal == null)
			{
				mortal = hit.collider.gameObject.GetComponent<Mortal>();
			}
			owner.StartOnlineShoot(hit.point);
			endPoint2 = hit.point;
			SendDamage(mortal, damage, hit.collider, endPoint2);
		}
		else
		{
			endPoint2 = startPoint + direction * distance;
		}
		owner.RiseEvent(owner, "OnlineShoot", endPoint2);
		ShowCharge(startPoint, endPoint2);
		yield break;
	}

	public void ShowCharge(Vector3 startPoint, Vector3 endPoint)
	{
		if (type != 0 || !chargePrefab || (Device.indexWeakDevice != 0 && !owner.isMine))
		{
			return;
		}
		GameObject gameObject = UnityEngine.Object.Instantiate(chargePrefab, startPoint, Quaternion.LookRotation(endPoint - startPoint)) as GameObject;
		OnChargeObj component = gameObject.GetComponent<OnChargeObj>();
		if (component != null)
		{
			if (ignoreColliders == null || ignoreColliders.Length == 0)
			{
				component.InitCharge(startPoint, endPoint, damage, ignoreCollider);
			}
			else
			{
				component.InitCharge(startPoint, endPoint, damage, ignoreColliders);
			}
		}
	}

	private OnChargeExplosion PrepareProjectile(GameObject obj, LayerMask layer, float damage)
	{
		Rigidbody rigidbody = obj.GetComponent<Rigidbody>();
		Collider collider = obj.GetComponent<Collider>();
		if (rigidbody == null)
		{
			rigidbody = obj.AddComponent<Rigidbody>();
		}
		if (collider == null)
		{
			collider = obj.AddComponent<Collider>();
		}
		OnChargeExplosion component = obj.GetComponent<OnChargeExplosion>();
		if (ignoreColliders == null || ignoreColliders.Length == 0)
		{
			component.InitCharge(obj.transform.position, obj.transform.position, damage, ignoreCollider);
		}
		else
		{
			component.InitCharge(obj.transform.position, obj.transform.position, damage, ignoreColliders);
		}
		rigidbody.useGravity = true;
		rigidbody.isKinematic = false;
		rigidbody.mass = weight;
		collider.isTrigger = false;
		collider.enabled = true;
		return component;
	}

	private void ShootProjectile(float strength, float maxDistance, Vector3 startPoint, Vector3 direction, LayerMask layer)
	{
		GameObject gameObject = null;
		gameObject = ((!settings.offlineMode && PhotonNetwork.connected) ? PhotonNetwork.Instantiate("Grenade/" + chargePrefab.name, startPoint, Quaternion.LookRotation(direction), 0) : (UnityEngine.Object.Instantiate(chargePrefab, startPoint, Quaternion.LookRotation(direction)) as GameObject));
		OnChargeExplosion onChargeExplosion = PrepareProjectile(gameObject, layer, damage);
		onChargeExplosion.AddForce((direction + directionModifire) * strength);
	}

	private void ShootHoming(float strength, float maxDistance, Vector3 startPoint, Vector3 direction, LayerMask layer)
	{
		GameObject gameObject = null;
		gameObject = ((!settings.offlineMode && PhotonNetwork.connected) ? PhotonNetwork.Instantiate("Grenade/" + chargePrefab.name, startPoint, Quaternion.LookRotation(direction), 0) : (UnityEngine.Object.Instantiate(chargePrefab, startPoint, Quaternion.LookRotation(direction)) as GameObject));
		OnChargeExplosionHoming onChargeExplosionHoming = PrepareHoming(gameObject, layer, damage);
		onChargeExplosionHoming.InvokeBlowUp();
	}

	private OnChargeExplosionHoming PrepareHoming(GameObject obj, LayerMask layer, float damage)
	{
		Rigidbody rigidbody = obj.GetComponent<Rigidbody>();
		Collider collider = obj.GetComponent<Collider>();
		if (rigidbody == null)
		{
			rigidbody = obj.AddComponent<Rigidbody>();
		}
		if (collider == null)
		{
			collider = obj.AddComponent<Collider>();
		}
		OnChargeExplosionHoming component = obj.GetComponent<OnChargeExplosionHoming>();
		TitanBehavior currentTitan = TitanSpawner.instance.currentTitan;
		component.initialPosition = owner.pointForShoot.transform.position;
		component.target = currentTitan.TargetDetector.nearestEnemy;
		if (component.maxHeight == 0f)
		{
			component.maxHeight = currentTitan.TargetDetector.homingMissleFlyHeight;
		}
		component.maxFlyDistance = owner.maxDistance;
		component.pointsCount = 10;
		if (ignoreColliders == null || ignoreColliders.Length == 0)
		{
			component.InitCharge(obj.transform.position, obj.transform.position, damage, ignoreCollider);
		}
		else
		{
			component.InitCharge(obj.transform.position, obj.transform.position, damage, ignoreColliders);
		}
		rigidbody.useGravity = false;
		rigidbody.isKinematic = true;
		rigidbody.mass = weight;
		collider.isTrigger = false;
		collider.enabled = true;
		return component;
	}

	private void ShootContinuous(float strength, float maxDistance, Vector3 startPoint, Vector3 direction, LayerMask layer, float distance)
	{
		wait = UpdateContinuousDamage;
		owner.StartCoroutine(wait(strength, maxDistance, startPoint, direction, layer, distance));
	}

	private IEnumerator UpdateContinuousDamage(float streng, float maxDistance, Vector3 startPoint, Vector3 direction, LayerMask layer, float distance)
	{
		RaycastHit hit = default(RaycastHit);
		Ray ray = new Ray(startPoint, direction);
		Vector3 endPoint2 = Vector3.zero;
		if (Physics.Raycast(ray, out hit, maxDistance, layer))
		{
			Mortal mortal = hit.collider.gameObject.GetComponent<Mortal>();
			if (mortal == null)
			{
				mortal = hit.collider.gameObject.GetComponentInChildren<Mortal>();
			}
			if (mortal == null)
			{
				mortal = hit.collider.gameObject.GetComponentInParent<Mortal>();
			}
			owner.StartOnlineShoot(hit.point);
			endPoint2 = hit.point;
			SendDamage(mortal, damage, hit.collider, endPoint2);
		}
		else
		{
			endPoint2 = startPoint + direction * distance;
		}
		owner.RiseEvent(owner, "OnlineShoot", endPoint2);
		ShowShootEffect(startPoint, endPoint2);
		yield break;
	}

	private void ShowShootEffect(Vector3 startPoint, Vector3 endPoint)
	{
		if (!chargePrefab || (Device.indexWeakDevice != 0 && !owner.isMine))
		{
			return;
		}
		GameObject gameObject = UnityEngine.Object.Instantiate(chargePrefab, startPoint, Quaternion.LookRotation(endPoint - startPoint)) as GameObject;
		OnChargeObj component = gameObject.GetComponent<OnChargeObj>();
		if (component != null)
		{
			if (ignoreColliders == null || ignoreColliders.Length == 0)
			{
				component.InitCharge(startPoint, endPoint, damage, ignoreCollider);
			}
			else
			{
				component.InitCharge(startPoint, endPoint, damage, ignoreColliders);
			}
		}
		(component as OnChargeContinuous).SetStart(owner.pointForShoot);
		if (TitanSpawner.instance.currentTitan != null && TitanSpawner.instance.currentTitan.TargetDetector.nearestEnemy != null)
		{
			(component as OnChargeContinuous).SetTarget(TitanSpawner.instance.currentTitan.TargetDetector.nearestEnemy.transform);
		}
		(component as OnChargeContinuous).SetEnd(endPoint);
	}

	private IEnumerator UpdateConeDamague(float damage, float streng, float maxDistance, Vector3 startPoint, Vector3 direction, LayerMask layer)
	{
		yield return new WaitForSeconds(0.3f);
		List<Mortal> demaged = new List<Mortal>();
		float cTime = 0f;
		Mortal closestObject2 = null;
		float xAngle = 0f - directionModifire.x + direction.x;
		float yAngle = 0f - directionModifire.y + direction.y;
		float zAngle = 0f - directionModifire.z + direction.z;
		if (updateTime <= 0f)
		{
			BCWDebug.LogError("updateTime = null " + owner.name);
		}
		while (true)
		{
			Vector3 newDirection = new Vector3(xAngle, yAngle, zAngle);
			Ray ray = new Ray(startPoint, newDirection);
			RaycastHit hit = default(RaycastHit);
			if (Physics.Raycast(ray, out hit, maxDistance, layer))
			{
				closestObject2 = hit.collider.gameObject.GetComponentInParent<Mortal>();
				if (!demaged.Contains(closestObject2))
				{
					demaged.Add(closestObject2);
					SendDamage(closestObject2, damage, hit.collider);
				}
			}
			zAngle += updateTime;
			if (zAngle < directionModifire.z + direction.z)
			{
				continue;
			}
			zAngle = 0f;
			yAngle += updateTime;
			if (!(yAngle < directionModifire.y + direction.y))
			{
				yAngle = 0f;
				xAngle += updateTime;
				if (!(xAngle < directionModifire.x + direction.x))
				{
					break;
				}
			}
		}
		wait = null;
	}

	private void ShootCone(float streng, float maxDistance, Vector3 startPoint, Vector3 direction, LayerMask layer)
	{
		if ((bool)chargePrefab)
		{
			UnityEngine.Object.Instantiate(chargePrefab, startPoint, Quaternion.LookRotation(direction));
		}
		waitCone = UpdateConeDamague;
		owner.StartCoroutine(waitCone(damage, streng, maxDistance, startPoint, direction, layer));
	}

	private OnChargeExplosion PrepareRemaining(GameObject obj, LayerMask layer, float damage)
	{
		Rigidbody rigidbody = obj.GetComponent<Rigidbody>();
		Collider collider = obj.GetComponent<Collider>();
		if (rigidbody == null)
		{
			rigidbody = obj.AddComponent<Rigidbody>();
		}
		if (collider == null)
		{
			collider = obj.AddComponent<Collider>();
		}
		OnChargeExplosion component = obj.GetComponent<OnChargeExplosion>();
		if (ignoreColliders == null || ignoreColliders.Length == 0)
		{
			component.InitCharge(obj.transform.position, obj.transform.position, damage, ignoreCollider);
		}
		else
		{
			component.InitCharge(obj.transform.position, obj.transform.position, damage, ignoreColliders);
		}
		rigidbody.useGravity = true;
		rigidbody.isKinematic = false;
		rigidbody.mass = weight;
		collider.isTrigger = false;
		collider.enabled = true;
		return component;
	}

	private void ShootRemaining(float strength, float maxDistance, Vector3 startPoint, Vector3 direction, LayerMask layer)
	{
		GameObject gameObject = null;
		gameObject = ((!settings.offlineMode && PhotonNetwork.connected) ? PhotonNetwork.Instantiate("Grenade/" + chargePrefab.name, startPoint, Quaternion.LookRotation(direction), 0) : (UnityEngine.Object.Instantiate(chargePrefab, startPoint, Quaternion.LookRotation(direction)) as GameObject));
		OnChargeExplosion onChargeExplosion = PrepareProjectile(gameObject, layer, damage);
		onChargeExplosion.AddForce((direction + directionModifire) * strength);
		remainingOnScene.AddLast(gameObject);
		if (remainingOnScene.Count <= maxCountOfRemainingOnScene)
		{
			return;
		}
		if (settings.offlineMode || !PhotonNetwork.connected)
		{
			if (remainingOnScene.First.Value != null)
			{
				UnityEngine.Object.Destroy(remainingOnScene.First.Value);
				remainingOnScene.RemoveFirst();
			}
			else
			{
				remainingOnScene.RemoveFirst();
			}
		}
		else if (remainingOnScene.First.Value != null)
		{
			PhotonNetwork.Destroy(remainingOnScene.First.Value);
			remainingOnScene.RemoveFirst();
		}
		else
		{
			remainingOnScene.RemoveFirst();
		}
	}

	private OnChargeWave PrepareGrowing(GameObject obj, LayerMask layer, float damage)
	{
		Rigidbody rigidbody = obj.GetComponent<Rigidbody>();
		Collider collider = obj.GetComponent<Collider>();
		if (rigidbody == null)
		{
			rigidbody = obj.AddComponent<Rigidbody>();
		}
		if (collider == null)
		{
			collider = obj.AddComponent<Collider>();
		}
		OnChargeWave component = obj.GetComponent<OnChargeWave>();
		if (ignoreColliders == null || ignoreColliders.Length == 0)
		{
			component.InitCharge(obj.transform.position, obj.transform.position, damage, ignoreCollider);
		}
		else
		{
			component.InitCharge(obj.transform.position, obj.transform.position, damage, ignoreColliders);
		}
		rigidbody.useGravity = false;
		rigidbody.isKinematic = false;
		rigidbody.mass = weight;
		collider.isTrigger = true;
		collider.enabled = true;
		return component;
	}

	private void ShootGrowing(float strength, float maxDistance, Vector3 startPoint, Vector3 direction, LayerMask layer)
	{
		GameObject gameObject = null;
		gameObject = ((!settings.offlineMode && PhotonNetwork.connected) ? PhotonNetwork.Instantiate("Grenade/" + chargePrefab.name, startPoint, Quaternion.LookRotation(direction), 0) : (UnityEngine.Object.Instantiate(chargePrefab, startPoint, Quaternion.LookRotation(direction)) as GameObject));
		OnChargeWave onChargeWave = PrepareGrowing(gameObject, layer, damage);
		onChargeWave.AddForce((direction + directionModifire) * strength);
		onChargeWave.IncreaseWave(owner.maxDistance);
	}

	public void SendDamage(Mortal mortal, float damage, Collider target, Vector3? hitPoint = null)
	{
		if ((bool)mortal)
		{
			if (TDMController.isTeamGameType && owner.isMine)
			{
				if (mortal is EntityBehavior)
				{
					EntityBehavior entityBehavior = mortal as EntityBehavior;
					PlayerBehavior playerBehavior = entityBehavior.getMainHuman() as PlayerBehavior;
					PlayerBehavior playerBehavior2 = GameController.instance.FindPlayer(entityBehavior.photonView.ownerId);
					if ((entityBehavior.getMainHuman() != null && playerBehavior != null && playerBehavior.localTeam == TDMController.myTeam && !entityBehavior.isMine) || (entityBehavior.privateCar && playerBehavior2 != null && playerBehavior2.localTeam == TDMController.myTeam))
					{
						return;
					}
				}
				else if (mortal is PlayerBehavior)
				{
					PlayerBehavior playerBehavior3 = mortal as PlayerBehavior;
					if (playerBehavior3.localTeam == TDMController.myTeam && !playerBehavior3.isMine)
					{
						return;
					}
				}
			}
			bool flag = false;
			if (target.tag == "ShootHead")
			{
				flag = true;
				mortal.ShowCriticalDamage();
				damage *= 1.5f;
			}
			if (mortal != GameController.instance.playerScript && !mortal.isDead && owner.isMine)
			{
				WalkWindow.instance.aimHUD.ShowAimHit(damage, damage * (float)owner.bulletInOneShoot / owner.TimeBetweenShots);
				if (!flag)
				{
					mortal.ShowNormalDamage();
				}
			}
			if (!owner.isMine)
			{
				return;
			}
			GameController.instance.playerScript.SetPlayerLastDamageInfo(mortal, flag);
			float distance = 0f;
			if (hitPoint.HasValue)
			{
				distance = Vector3.Distance(owner.transform.position, hitPoint.Value);
			}
			damage *= PlayerBehavior.MyPlayer.weaponManager.GetDistanceDamageModifier(distance);
			mortal.GetDamage((int)damage, (int)damageType, owner.ViewID, owner.transform.position, hitPoint);
			if (effects != null)
			{
				WeaponEffectSettings[] array = effects;
				foreach (WeaponEffectSettings weaponEffectSettings in array)
				{
					mortal.AddWeaponEffect((int)weaponEffectSettings.effectType, (int)weaponEffectSettings.damageType, weaponEffectSettings.effectDuration, weaponEffectSettings.effectPower, owner.ViewID);
				}
			}
			owner.OnDamage();
		}
		else
		{
			owner.OnHit();
		}
	}
}
